package ast;

import java.io.PrintStream;
import java.util.Map;
import java.util.Scanner;
import java.util.Stack;

import exceptions.UninitializedVariableException;

public class IdentExpr extends Expr {
    public final String ident;

    public IdentExpr(String i, Location loc) {
        super(loc);
        ident = i;
    }

    public void print(PrintStream ps) {
        ps.print(ident);
    }

    // TODO: use stack to handle scope layers
    public AbstractValue evaluate(Stack<Map<String, AbstractValue>> stateStack, Scanner scanner) throws Exception {

        // clone the stack
        Stack<Map<String, AbstractValue>> cloneStateStack = new Stack<>();
        cloneStateStack.addAll(stateStack);
        boolean found = false;
        AbstractValue value = null;
        // traverse the stack to find the variable
        while (!cloneStateStack.isEmpty()) {
            Map<String, AbstractValue> scopeState = cloneStateStack.pop();
            if (scopeState.containsKey(ident)) {
                found = true;
                value = scopeState.get(ident);
                break;
            }
        }

        // if the variable is not defined at all, throw an exception
        if (!found) {
            throw new Exception("Variable " + ident + " not defined");
        }

        // if the variable is not initialized, throw an exception
        if (value == null) {
            throw new UninitializedVariableException("Variable " + ident + " not initialized");
        }
        return value;
    }
}
